#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

#define KEY_PIN 3  // IO3 按键，切换时间
#define D5_PIN 1   // IO1 LED，显示
#define ON_PIN 2   // IO2 继电器控制

int hourSet = 4;
unsigned long endTime = 0;              // 断电时间
unsigned long hourMs = 60 * 60 * 1000;  // 1小时的毫秒数（60分钟 * 60秒 * 1000毫秒）
int mode = 1;                           // 1-倒计时模式，2-定时模式，3-循环定时
int schedulingHour[12];                 // 定时设置，对应12个小时，{1,0,0,0,0,0,0,0,0,1,0,0} --第1小时和第10小时接通，其余断电
String schedulingHourDisplay = "";

// 设置 WiFi 热点名称和密码
const char *ssid = "ESP-B12579DB-46AB-4C31-A198";
const char *password = "123456780";

// 创建一个 Web 服务器，监听 80 端口
ESP8266WebServer server(80);

// 按键改变设定定时时间 3/6
void IRAM_ATTR changeTime() {
  mode = 1;
  if (hourSet == 4) {
    hourSet = 8;
  } else {
    hourSet = 4;
  }
  endTime = millis() + hourSet * hourMs;
  digitalWrite(ON_PIN, HIGH);
  digitalWrite(D5_PIN, LOW);
}

void setup() {
  // 引脚初始化
  pinMode(KEY_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(KEY_PIN), changeTime, FALLING);
  pinMode(D5_PIN, OUTPUT);
  pinMode(ON_PIN, OUTPUT);
  delay(50);
  digitalWrite(D5_PIN, LOW);  // led默认熄灭
  digitalWrite(ON_PIN, LOW);  // 继电器初始化

  // wifi热点初始化
  WiFi.softAP(ssid, password);

  // Web 服务器处理
  server.on("/", HTTP_GET, handleRoot);
  server.onNotFound(handleRoot);
  server.on("/scheduling", HTTP_GET, handleRoot);
  server.begin();

  delay(3000);
  digitalWrite(ON_PIN, HIGH);  // 继电器上电
  endTime = millis() + hourSet * hourMs;
}

void loop() {
  // 处理所有客户端请求
  server.handleClient();

  unsigned long currentTime = millis();    // 获取当前时间，单位为毫秒
  int hour = floor(currentTime / hourMs);  // 第几个小时

  if (mode == 2 || mode == 3) {
    if (mode == 2 && hour > 12) {
      digitalWrite(ON_PIN, LOW);
    } else {
      hour = hour % 12;
      if (schedulingHour[hour] == 1) {
        digitalWrite(ON_PIN, HIGH);  // 设置为高电平
      } else {
        digitalWrite(ON_PIN, LOW);  // 设置为低电平
      }
    }
  } else {
    if (currentTime >= endTime) {
      // 计时完成，将 GPIO2 置为低电平
      digitalWrite(ON_PIN, LOW);
    } else if (currentTime % (10 * 1000) < 500) {
      // 每30s通过led显示一次剩余时间
      int remainHours = ceil((endTime - currentTime) / hourMs);  // 转换为小时，向上取整，1.2 => 2
      for (int i = 0; i <= remainHours; i++) {
        digitalWrite(D5_PIN, HIGH);
        delay(300);
        digitalWrite(D5_PIN, LOW);
        delay(300);
      }
    }
  }

  delay(500);
}

// 根路径处理函数
void handleRoot() {
  unsigned long currentTime = millis();
  String hourVal = server.arg("h");
  String schedulingVal = server.arg("s");
  String loop = server.arg("loop");

  if (schedulingVal.length() == 12) {
    if (loop == "1") {
      mode = 3;
    } else {
      mode = 2;
    }
    schedulingHourDisplay = "";
    for (int i = 0; i < schedulingVal.length(); i++) {
      schedulingHour[i] = schedulingVal.charAt(i) - '0';  // 将字符转换为对应的数字
      if (schedulingHour[i] == 1) {
        schedulingHourDisplay += String(i + 1);
        schedulingHourDisplay += "，";
      }
    }
    server.sendHeader("Location", "/", true);  // 301 永久重定向
    server.send(301);                          // 返回 301 状态码
  } else if (hourVal.length() >= 1) {
    mode = 1;
    hourSet = hourVal.toInt();
    if (hourSet > 0) {
      endTime = currentTime + hourSet * hourMs;
      digitalWrite(ON_PIN, HIGH);
      digitalWrite(D5_PIN, LOW);
    }
    server.sendHeader("Location", "/", true);  // 301 永久重定向
    server.send(301);                          // 返回 301 状态码
  }

  String htmlInfo = "";
  if (mode == 1) {
    int remainMinute = ceil((endTime - currentTime) / 1000 / 60);
    htmlInfo += "<h2>倒计时，<span style='color: #19c721'>";
    htmlInfo += hourSet;
    htmlInfo += "小时</span>，<span style='color: #c53737'>";
    htmlInfo += remainMinute;
    htmlInfo += "分钟</span>后断电</h2>";
  } else {
    int hour = floor(currentTime / hourMs);  // 第几个小时

    if (mode == 2) {
      htmlInfo += "<h2>单次定时，通电时间第<span style='color: #19c721'>";
    } else {
      htmlInfo += "<h2>循环定时，通电时间第<span style='color: #19c721'>";
    }
    htmlInfo += schedulingHourDisplay;
    htmlInfo += "小时</span>，当前第<span style='color: #c53737'>";
    htmlInfo += String(hour + 1);
    htmlInfo += "</span>小时</h2>";
  }

  String html = "<!DOCTYPE html><html lang='en'><head><meta name='viewport'content='width=device-width, initial-scale=1.0'><meta charset='utf-8'/>";
  html += "<style>#scheduling{display:flex;margin-top:30px;flex-wrap:wrap}#scheduling div{margin:2px;text-align:center;background-color:#e6e5e5;line-height:50px;width:15%}#scheduling div.on{color:white;background-color:#c53737}</style></head><body>";
  html += htmlInfo;
  html += "<h3><a href='/?h=1'>定时1小时</a></h3><h3><a href='/?h=2'>定时2小时</a></h3><h3><a href='/?h=3'>定时3小时</a></h3><h3><a href='/?h=4'>定时4小时</a></h3><h3><a href='/?h=5'>定时5小时</a></h3><h3><a href='/?h=6'>定时6小时</a></h3><h3><a href='/?h=8'>定时8小时</a></h3><h3><a href='/?h=10'>定时10小时</a></h3><h3><a href='/?h=12'>定时12小时</a></h3>";
  html += "<div></div><div id=\"scheduling\"></div><div style=\"margin-top: 20px; display: flex; align-items: center;\"><input type=\"checkbox\"id=\"loop\"style=\"height: 24px; width: 24px;\"><span>循环定时</span><button onclick=\"updateHours()\"style=\"width: 120px; line-height: 60px; margin-left: 30px;\">设置</button></div>";
  html += "<script>var hours=[0,0,0,0,0,0,0,0,0,0,0,0];function showSchedulingDom(){var html=\"\";hours.forEach((h,i)=>{if(h>0){html+=`<div class=\"on\"onClick=\"setHour(${i})\">${i+1}</div>`}else{html+=`<div onClick=\"setHour(${i})\">${i+1}</div>`}});document.getElementById(\"scheduling\").innerHTML=html}showSchedulingDom();function setHour(i){hours[i]=1-hours[i];showSchedulingDom()}function updateHours(){var loop=document.getElementById(\"loop\").checked?\"1\":\"0\";location.href=\"/scheduling?s=\"+hours.join(\"\")+\"&loop=\"+loop}</script></body></html>";

  server.send(200, "text/html", html);
}
